package com.boarsoft.boar.log.action;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;

import org.elasticsearch.action.ActionFuture;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.admin.indices.stats.IndexStats;
import org.elasticsearch.action.admin.indices.stats.IndicesStatsRequest;
import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.boarsoft.bean.ReplyInfo;
import com.boarsoft.boar.log.bean.LogQueryParam;
import com.boarsoft.common.Util;
import com.boarsoft.common.dao.PagedResult;
import com.boarsoft.elasticsearch.ElasticSearchClient;

@RestController
@RequestMapping("/es/index")
public class EsLogIndexAction {
	private static final Logger log = LoggerFactory.getLogger(EsLogIndexAction.class);

	@Autowired
	private ElasticSearchClient esClient;

	@RequestMapping("/index.do")
	// @Authorized(code = "log.es.index.query")
	public void index(LogQueryParam param) {

	}

	/**
	 * 查询指定的index中的日志
	 */
	@RequestMapping("/query.do")
	// @Authorized(code = "log.es.index.query")
	public ReplyInfo<Object> query(LogQueryParam p) {
		Client client = esClient.getClient();
		SearchRequestBuilder srb = client.prepareSearch(p.getTarget());
		BoolQueryBuilder bqb = QueryBuilders.boolQuery();
		// 日志级别
		bqb.must(QueryBuilders.rangeQuery("level").lte(p.getLevel()));
		// 日志跟踪ID（如：流程ID）
		if (Util.strIsNotEmpty(p.getTraceId())) {
			bqb.must(QueryBuilders.termQuery("trace.keyword", p.getTraceId()));
		}
		// 日志来源应用实例的地址
		if (Util.strIsNotEmpty(p.getAddr())) {
			bqb.must(QueryBuilders.termQuery("addr.keyword", p.getAddr()));
		}
		if (Util.strIsNotEmpty(p.getThreadName())) {
			bqb.must(QueryBuilders.termQuery("thread.keyword", p.getThreadName()));
		}
		if (Util.strIsNotEmpty(p.getRegx())) {
			bqb.must(QueryBuilders.regexpQuery("message", p.getRegx()));
		}
		if (Util.strIsNotEmpty(p.getKey())) {
			if (p.getKey().contains("*") || p.getKey().contains("?")) {
				bqb.must(QueryBuilders.wildcardQuery("message", p.getKey()));
			} else {
				bqb.must(QueryBuilders.termQuery("message", p.getKey()));
			}
		}
		//
		if (Util.strIsNotEmpty(p.getLogger())) {
			bqb.must(QueryBuilders.termQuery("logger", p.getLogger()));
		}
		if (p.getStartTime() != null) {
			RangeQueryBuilder rqb = QueryBuilders.rangeQuery("time");
			rqb.gte(p.getStartTime()); // 写入ES时存的是long
			if (p.getEndTime() != null) {
				p.setEndTime(new Date().getTime());
			}
			rqb.lte(p.getEndTime()); //
			bqb.must(rqb); //
		}
		//
		srb.setQuery(bqb);
		srb.addSort("time", SortOrder.DESC); // 倒序查询
		srb.setSize(p.getPageSize()); //
		SearchResponse sr = null;
		try {
			sr = srb.get();
		} catch (IndexNotFoundException e) {
			log.error("Index {} not found", p.getTarget(), e);
			return new ReplyInfo<Object>("No such index");
		}
		SearchHits hits = sr.getHits();
		log.info("Total {} records found", hits.getTotalHits());
		SearchHit[] sha = hits.getHits();
		// StringBuilder sb = new StringBuilder();
		Map<String, List<String>> rm = new HashMap<String, List<String>>();
		if (sha.length > 0) {
			// 正序添加
			for (int i = sha.length - 1; i >= 0; i--) {
				SearchHit h = sha[i];
				Map<String, Object> m = h.getSourceAsMap();
				// sb.append((String) m.get("message")).append("\n");
				String addr = (String) m.get("addr");
				String msg = (String) m.get("message");
				List<String> lt = rm.get(addr);
				if (lt == null) {
					lt = new LinkedList<String>();
					rm.put(addr, lt);
				}
				lt.add(msg.concat("\n"));
			}
		}
		return new ReplyInfo<Object>(true, rm);
	}

	/**
	 * 查询elasticsearch中所有的index
	 */
	@RequestMapping("/list.do")
	// @Authorized(code = "log.es.index.list")
	public ReplyInfo<Object> list(int pageNo, int pageSize) {
		Client client = esClient.getClient();
		ActionFuture<IndicesStatsResponse> isr = client.admin().indices()//
				.stats(new IndicesStatsRequest().all());
		// IndicesAdminClient iac = client.admin().indices();
		Map<String, IndexStats> ism = isr.actionGet().getIndices();
		List<Map<String, Object>> lt = new ArrayList<Map<String, Object>>();
		for (String k : ism.keySet()) {
			Map<String, Object> m = new HashMap<String, Object>();
			IndexStats s = ism.get(k);
			m.put("index", s.getIndex());
			m.put("shards", s.getShards().length);
			m.put("docs", s.getTotal().getDocs().getCount());
			lt.add(m);
		}
		PagedResult<Map<String, Object>> pr = new PagedResult<Map<String, Object>>(//
				lt.size(), lt, pageNo, pageSize);
		return new ReplyInfo<Object>(true, pr);
	}

	/**
	 * 查询指定服务的某个实例
	 */
	@RequestMapping("/truncate.do")
	// @Authorized(code = "log.truncate")
	public ReplyInfo<Object> truncate(String target) {
		try {
			esClient.truncate(target);
			return ReplyInfo.SUCCESS;
		} catch (InterruptedException | ExecutionException e) {
			log.error("Error on truncate index {}", target, e);
			return new ReplyInfo<Object>(false, e.getMessage());
		}
	}

	/**
	 * 查询指定服务的某个实例
	 */
	@RequestMapping("/drop.do")
	// @Authorized(code = "log.truncate")
	public ReplyInfo<Object> drop(String target) {
		Client client = esClient.getClient();
		try {
			client.admin().indices().delete(new DeleteIndexRequest(target)).get();
			return ReplyInfo.SUCCESS;
		} catch (InterruptedException | ExecutionException e) {
			log.error("Error on drop index {}", target, e);
			return new ReplyInfo<Object>(false, e.getMessage());
		}
	}

}